<template>
  <div class="image-cropper">
    <div class="cropper-content">
      <!-- 裁剪区域 -->
      <div class="cropper-container">
        <vueCropper
          ref="cropper"
          :img="option.img"
          :output-size="option.outputSize"
          :output-type="option.outputType"
          :info="true"
          :full="option.full"
          :can-move="option.canMove"
          :can-move-box="option.canMoveBox"
          :original="option.original"
          :auto-crop="option.autoCrop"
          :auto-crop-width="option.autoCropWidth"
          :auto-crop-height="option.autoCropHeight"
          :fixed-box="option.fixedBox"
          :fixed="option.fixed"
          :fixed-number="option.fixedNumber"
          :enlarge="option.enlarge"
          :can-scale="option.canScale"
          :center-box="option.centerBox"
          :info-true="option.infoTrue"
          :mode="option.mode"
          @real-time="onRealTime"
        />
      </div>
    </div>

    <!-- 操作按钮区域 -->
    <div class="footer-btn">
      <!-- 缩放旋转按钮组 -->
      <div class="scope-btn">
        <el-tooltip content="放大" placement="top">
          <el-button type="primary" circle @click="changeScale(1)">
            <el-icon><ZoomIn /></el-icon>
          </el-button>
        </el-tooltip>

        <el-tooltip content="缩小" placement="top">
          <el-button type="primary" circle @click="changeScale(-1)">
            <el-icon><ZoomOut /></el-icon>
          </el-button>
        </el-tooltip>

        <el-tooltip content="逆时针旋转" placement="top">
          <el-button type="primary" circle @click="rotateLeft">
            <el-icon><RefreshLeft /></el-icon>
          </el-button>
        </el-tooltip>

        <el-tooltip content="顺时针旋转" placement="top">
          <el-button type="primary" circle @click="rotateRight">
            <el-icon><RefreshRight /></el-icon>
          </el-button>
        </el-tooltip>

        <el-tooltip content="重置" placement="top">
          <el-button type="info" circle @click="resetCropper">
            <el-icon><Refresh /></el-icon>
          </el-button>
        </el-tooltip>
      </div>

      <!-- 确认上传按钮 -->
      <div class="upload-btn">
        <el-tooltip content="上传裁剪后的图片" placement="top">
          <el-button
            type="success"
            :disabled="isDisabled || !option.img"
            @click="uploadImg('base64')"
            :loading="uploading"
          >
            <el-icon><Upload /></el-icon>
            确认上传
          </el-button>
        </el-tooltip>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, onMounted, nextTick, watch, computed } from "vue";
// @ts-ignore
import { VueCropper } from "vue-cropper";
import "vue-cropper/dist/index.css";
import {
  ZoomIn,
  ZoomOut,
  RefreshLeft,
  RefreshRight,
  Refresh,
  Upload,
} from "@element-plus/icons-vue";

// Props定义
const props = defineProps({
  imgFile: {
    type: Object,
    required: true,
  },
  // 裁剪框宽高比 [w,h]，如 [3,1]
  fixedNumber: {
    type: Array,
    default: () => [1, 1],
  },
  // 是否固定比例
  fixed: {
    type: Boolean,
    default: true,
  },
  // 可选：自定义初始裁剪框宽高（不传则自动按比例适配容器）
  initialCropWidth: {
    type: Number,
    default: 0,
  },
  initialCropHeight: {
    type: Number,
    default: 0,
  },
  // 预览尺寸配置
  previews: {
    type: Array,
    default: () => [
      { label: "圆形头像", width: 100, height: 100, borderRadius: "50%" },
      { label: "方形", width: 150, height: 150 },
      { label: "矩形", width: 200, height: 100 },
    ],
  },
});

// Emits定义
const emit = defineEmits(["upload-files", "cropper-ready", "cropper-error"]);

// 响应式数据
const isDisabled = ref(false);
const uploading = ref(false);
const previewDataUrl = ref("");
const cropper = ref(null);

// 裁剪配置
const option = reactive({
  img: "", // 裁剪图片的地址
  outputSize: 0.9, // 0-1，生成图片质量(提高默认质量)
  full: false, // 是否输出原图比例
  outputType: "png", // 生成图片格式
  canMove: true, // 图片是否可移动
  original: true, // 按原始比例渲染，提高预览-导出一致性
  canMoveBox: true, // 截图框能否拖动
  autoCrop: true, // 是否默认生成截图框
  autoCropWidth: 400, // 默认截图框宽度
  autoCropHeight: 300, // 默认截图框高度
  fixedBox: false, // 固定截图框大小
  fixed: true, // 固定比例（由props.fixed控制）
  fixedNumber: [1, 1], // 比例（由props.fixedNumber控制）
  enlarge: 1, // 导出放大倍数（挂载时调整为dpr）
  info: true, // 裁剪框大小信息
  canScale: true, // 允许滚轮缩放
  centerBox: true, // 限制在图片内
  infoTrue: true, // 展示真实输出宽高
  mode: "contain", // 图片适应模式
});

// 计算属性 - 获取预览配置
const previews = computed(() => {
  return props.previews.map((preview) => {
    // 为预览项添加transform样式
    return {
      ...preview,
      transform: preview.borderRadius === "50%" ? "scale(1.1)" : "scale(1)",
    };
  });
});

// 组件挂载后初始化
onMounted(() => {
  nextTick(() => {
    // 根据设备像素比设置导出放大倍数，提升导出清晰度并匹配预览
    const dpr = Math.max(1, Math.min(2, window.devicePixelRatio || 1));
    option.enlarge = dpr;
    updateImage();
    emit("cropper-ready");
  });
});

// 更新裁剪器配置
const updateCropperOptions = () => {
  // 同步固定比例与比例参数
  option.fixed = props.fixed;
  if (
    Array.isArray(props.fixedNumber) &&
    props.fixedNumber.length === 2 &&
    Number(props.fixedNumber[0]) > 0 &&
    Number(props.fixedNumber[1]) > 0
  ) {
    option.fixedNumber = [
      Number(props.fixedNumber[0]),
      Number(props.fixedNumber[1]),
    ];
  }

  // 计算截图框尺寸：优先使用传入的初始尺寸，其次根据容器和比例自适应
  const containerWidth = 500;
  const containerHeight = 400;
  let cropW = props.initialCropWidth || option.autoCropWidth;
  let cropH = props.initialCropHeight || option.autoCropHeight;

  if (!props.initialCropWidth || !props.initialCropHeight) {
    const [rw, rh] = option.fixedNumber;
    const ratio = rw / rh;
    // 在容器内尽量放大，保留边距
    const maxW = containerWidth - 40;
    const maxH = containerHeight - 40;
    // 先按宽度填充
    let w = Math.min(maxW, option.autoCropWidth);
    let h = Math.round(w / ratio);
    if (h > maxH) {
      h = maxH;
      w = Math.round(h * ratio);
    }
    cropW = w;
    cropH = h;
  }

  option.autoCropWidth = cropW;
  option.autoCropHeight = cropH;
};

// 监听props变化
watch(
  () => [
    props.fixed,
    props.fixedNumber,
    props.initialCropWidth,
    props.initialCropHeight,
  ],
  () => {
    updateCropperOptions();
  },
  { immediate: true, deep: true }
);

// 监听imgFile变化
watch(
  () => props.imgFile,
  () => {
    updateImage();
  },
  { deep: true }
);

// 更新图片
const updateImage = () => {
  console.log("updateImage called with imgFile:", props.imgFile);

  if (props.imgFile) {
    try {
      // 1. el-upload file对象
      if (props.imgFile.raw instanceof File) {
        console.log("Processing el-upload file object");
        const url = URL.createObjectURL(props.imgFile.raw);
        option.img = url;
        console.log("Image URL set:", url);
        return;
      }
      // 2. base64字符串
      if (
        typeof props.imgFile === "string" &&
        props.imgFile.startsWith("data:image")
      ) {
        console.log("Processing base64 string");
        option.img = props.imgFile;
        return;
      }
      // 3. blob对象
      if (props.imgFile instanceof Blob) {
        console.log("Processing blob object");
        const url = URL.createObjectURL(props.imgFile);
        option.img = url;
        return;
      }
      // 4. url字段
      if (props.imgFile.url) {
        console.log("Processing url field");
        option.img = props.imgFile.url;
        return;
      }
    } catch (error) {
      console.error("图片加载失败:", error);
      emit("cropper-error", error);
    }
  }
  console.log("No valid imgFile, setting empty string");
  option.img = "";
};

// 实时预览回调
const onRealTime = (data) => {
  previewDataUrl.value = data;
};

// 方法定义
const changeScale = (num) => {
  // 图片缩放
  num = num || 1;
  cropper.value?.changeScale(num);
};

const rotateLeft = () => {
  // 向左旋转
  cropper.value?.rotateLeft();
};

const rotateRight = () => {
  // 向右旋转
  cropper.value?.rotateRight();
};

const resetCropper = () => {
  // 重置裁剪器
  if (cropper.value) {
    cropper.value.reset();
    // 重新设置裁剪框大小
    nextTick(() => {
      cropper.value?.goAutoCrop();
    });
  }
};

const uploadImg = async (type) => {
  // 将剪裁好的图片回传给父组件
  if (!cropper.value || !option.img) {
    return;
  }

  isDisabled.value = true;
  uploading.value = true;

  try {
    const done = (data) => {
      emit("upload-files", data);
      isDisabled.value = false;
      uploading.value = false;
    };

    if (type === "blob") {
      cropper.value.getCropBlob((data) => {
        done(data);
      });
    } else {
      cropper.value.getCropData((data) => {
        done(data);
      });
    }
  } catch (error) {
    console.error("图片上传失败:", error);
    isDisabled.value = false;
    uploading.value = false;
    emit("cropper-error", error);
  }
};

// 暴露方法给父组件
defineExpose({
  update: updateImage,
  reset: resetCropper,
  rotateLeft,
  rotateRight,
  isDisabled,
  uploadImg,
  getCropperInstance: () => cropper.value,
});
</script>

<style lang="scss" scoped>
.image-cropper {
  width: 100%;
  max-width: 900px;
  margin: 0 auto;

  .cropper-content {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
    justify-content: center;
    align-items: flex-start;
    margin-bottom: 20px;

    .cropper-container {
      width: 500px;
      height: 400px;
      overflow: hidden;
      position: relative;
      border: 1px solid #e0e0e0;
      background: #f9f9f9;
      border-radius: 8px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);

      :deep(.vue-cropper) {
        width: 100%;
        height: 100%;
        background: transparent;

        .cropper-view-box {
          border-radius: 4px;
          outline: 2px solid #409eff;
          outline-color: rgba(64, 158, 255, 0.8);
        }

        .cropper-face {
          background-color: transparent;
        }

        .cropper-line,
        .cropper-point {
          background-color: #409eff;
        }

        .cropper-modal {
          background: rgba(0, 0, 0, 0.5);
        }
      }
    }
  }

  .footer-btn {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: 15px;
    padding: 15px 0;
    border-top: 1px solid #e0e0e0;

    .scope-btn {
      display: flex;
      gap: 10px;
      flex-wrap: wrap;
    }

    .upload-btn {
      margin-left: auto;
    }
  }

  @media (max-width: 768px) {
    .cropper-content {
      flex-direction: column;
      align-items: center;

      .cropper-container {
        width: 100%;
        max-width: 500px;
        height: 350px;
      }
    }

    .footer-btn {
      flex-direction: column;

      .scope-btn {
        justify-content: center;
      }

      .upload-btn {
        margin-left: 0;
      }
    }
  }
}
</style>
